package com.cly.pay.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cly.api.clients.OrderClient;
import com.cly.api.clients.UserClient;
import com.cly.common.entity.order.po.Order;
import com.cly.common.entity.pay.dto.PayDTO;
import com.cly.common.entity.pay.dto.PayOrderFormDto;
import com.cly.common.entity.pay.po.PayOrder;
import com.cly.common.entity.result.Result;
import com.cly.common.exception.CommonException;
import com.cly.common.util.ThreadLocalUtil;
import com.cly.pay.mapper.PayMapper;
import com.cly.pay.service.PayService;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class PayServiceImpl extends ServiceImpl<PayMapper, PayOrder> implements PayService {
    @Autowired
    private PayMapper payMapper;
    @Autowired
    private  RabbitTemplate rabbitTemplate;

    @Autowired
    private CorrelationData correlationData;

    @Autowired
    private UserClient userClient;

    @Autowired
    private OrderClient orderClient;

    /**
     * 创建支付订单
     * @param payDTO
     * @return
     */
    @Override
    public Result createPayOrder(PayDTO payDTO) {
        // 检查该订单是否存在支付订单
        PayOrder oldPayOrder = lambdaQuery().eq(PayOrder::getOrderId, payDTO.getOrderId()).one();
        if(oldPayOrder == null){
            // 说明不存在该支付订单，创建支付订单，保存
            PayOrder payOrder = BeanUtil.copyProperties(payDTO, PayOrder.class);
            payOrder.setPayOrderNo(IdWorker.getId());
            payOrder.setUserId(ThreadLocalUtil.get());
            payOrder.setAmount(payDTO.getAmount());
            payOrder.setPayType(payDTO.getPayType());
            // 设置过期时间
            payOrder.setPayOverTime(LocalDateTime.now().plusMinutes(30L));
            this.save(payOrder);
            return Result.success();
        }
        // 订单存在，判断支付类似是否一致
        if(!oldPayOrder.getPayType().equals(payDTO.getPayType())){
            // 不一致，修改支付类型，重写保存
            oldPayOrder.setPayType(payDTO.getPayType());
            this.updateById(oldPayOrder);
            return Result.success();
        }else {
            return Result.error("该订单已存在支付订单");
        }
    }

    /**
     * 尝试支付
     * @param payOrderFormDto
     */
    @Override
    @GlobalTransactional
    public void tryPay(PayOrderFormDto payOrderFormDto) {
        // 先检查当前支付订单是否已经支付
        PayOrder payOrder = lambdaQuery().eq(PayOrder::getOrderId, payOrderFormDto.getOrderId()).one();
        if(payOrder == null){
            // 说明不存在该支付订单，直接返回
            throw new CommonException("当前支付不存在!!");
        }
        if(payOrder.getStatus() == 2){
            throw new CommonException("当前支付已过期!!");
        }
        if(payOrder.getStatus() == 3){
            throw new CommonException("当前支付已完成!!");
        }
        // 说明当前支付订单存在且未完成支付
        // TODO  支付密码校验

        // 扣减余额
        try {
            userClient.deductMoney(payOrderFormDto.getPayPwd(), payOrder.getAmount());
        } catch (Exception e) {
            throw new CommonException("余额支付失败",e);
        }
        // 扣减余额成功，修改支付订单状态
        try {
            this.lambdaUpdate().eq(PayOrder::getOrderId, payOrderFormDto.getOrderId())
                    .set(PayOrder::getStatus, 3).update();
        } catch (Exception e) {
            throw new CommonException("修改支付订单状态失败",e);
        }
        // 修改订单状态
//        orderClient.updateOrderStatus(payOrderFormDto.getOrderId(), 2);
        Map<String, Object> message = new HashMap<>();
        message.put("orderId", payOrderFormDto.getOrderId());
        message.put("status", 2);
        try {
            rabbitTemplate.convertAndSend("pay.direct", "pay.status",
                    message,  correlationData);
        } catch (AmqpException e) {
            log.error("生产者发送支付状态失败:{}", e);
        }
    }

}
